setClass("LLEReducer",contains="Reducer",
		representation(
				.knn="matrix",
				.weights="list"
		),
		prototype=prototype(
				.description="LLE Reducer Class"
		),
		validity=function(.Object){
			if(! is(.Object@.dimChooser,"MDSDimChooser")){
				stop("LLEReducer must be initialized by LLEDimChooser object. LLEReducer was initialized by ",class(.Object@.dimChooser))
			}
		}
)

#methods

setMethod("initialize",
		signature="LLEReducer",
		function(.Object,dimChooser,...){
			.Object <-callNextMethod(.Object,dimChooser,...);
			return(.Object)
		})

#helper Methods
#Function compiled to R bytecode
interBIC <-function(rowNum,tmpData,weightMatrix){
	#weighted sum of K nearest neighbour vectors
	colSums(weightMatrix[rowNum,]*tmpData)
}
interBIC <-cmpfun(interBIC)
BIC <- function(K,tmpData,rows,cols){ 
	knn<-find_nn_k(tmpData,K)
	weightMatrix <-find_weights(knn,tmpData,m=3)$wgts
	approxSetMatrix <- do.call(rbind,lapply(1:rows,FUN=interBIC,tmpData,weightMatrix))
	tmp <-approxSetMatrix - tmpData
	approxDist <-sum(rowSums( tmp*tmp ))
	return( cols*rows*log(approxDist) +rows*K*log(rows))
}
BIC <-cmpfun(BIC)

setMethod("reduce",
		signature="LLEReducer",
		definition=function(.Object,inputSet,...){
			.Object@.tmpData		<-as.matrix(inputSet)
			dims <- dim(.Object@.tmpData)
			rows <- dims[1]
			cols <- dims[2]
				
			#encapsulate this function in reduce method
			
			#bicValues <- unlist(lapply(1:{rows/2},FUN=BIC,.Object@.tmpData,rows,cols))#O(rows^2) very bad
			#O(rows^2) very bad
			bicValues <-
					foreach( k=seq( from=1, to={rows/2}, by=1 )) %dopar%{
						BIC(k,.Object@.tmpData,rows,cols)
					}
			bicValues <-unlist(bicValues)		
			optimalKnnNumber <-which.min(bicValues)
			#optimal number of KNN
			.Object@.knn<-find_nn_k(.Object@.tmpData,optimalKnnNumber)
			.Object@.weights <-find_weights(.Object@.knn,.Object@.tmpData,m=3)
			
			#test for 1:(rows -1) dimensions	
			dim <-chooseBest(.Object@.dimChooser,.Object)
			retSet <-find_coords(.Object@.weights$wgts,.Object@.knn,rows,cols,dim)
			.Object@.tmpData <- matrix()
			.Object@.resEnv$savedSet <-as.matrix(retSet) 
			return(.Object@.resEnv$savedSet)
			
		}) 
